package cmd

import (
	"fmt"
	"github.com/gin-contrib/static"
	"github.com/gin-gonic/gin"
	jsoniter "github.com/json-iterator/go"
	_ "github.com/mitchellh/mapstructure"
	"github.com/natefinch/lumberjack"
	"github.com/spf13/viper"
	"goback/config/model"
	"goback/constant"
	"goback/controller"
	mysqlDri "gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
	"log"
	"net/http"
	"os"
	"runtime/debug"
	"strings"
	"time"
	"unsafe"
)

var (
	Db *gorm.DB = nil
)

func Boot() error {
	var err error = nil
	err = initViper()
	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
		return err
	}
	var mysql model.Mysql
	// 映射配置到结构体
	err = viper.Sub("mysql").Unmarshal(&mysql)

	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
	// 创建一个带有 lumberjack.Logger 的 io.Writer
	logFile := &lumberjack.Logger{
		Filename:   "app.log", // 日志文件路径
		MaxSize:    10,        // 每个日志文件的最大大小（MB）
		MaxAge:     30,        // 文件最多保存多少天
		MaxBackups: 3,         // 最多保存多少个旧文件
		LocalTime:  true,      // 使用本地时间而非 UTC
	}
	// 将该 io.Writer 设置为 log 包的输出目标
	log.SetOutput(logFile)
	//数据库连接
	dsn := "%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=True"
	dsn = fmt.Sprintf(dsn, mysql.User, mysql.Pwd, mysql.Host, mysql.Port, mysql.Database, mysql.Charset)
	// 创建一个自定义的naming strategy，这里使用schema.SnakeCaseStrategyNew，将字段名转换为蛇形命名（小写下划线分隔）
	namingStrategy := schema.NamingStrategy{
		TablePrefix:   "",   // 表前缀
		SingularTable: true, // 是否启用单数表名
		NameReplacer:  nil,  // 自定义命名替换函数
	}
	jsoniter.RegisterTypeDecoderFunc("time.Time", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
		t, err := time.Parse("2006-01-02 15:04:05", iter.ReadString())
		if err != nil {
			iter.ReportError("decode time.Time", err.Error())
			return
		}
		*((*time.Time)(ptr)) = t
	})
	jsoniter.RegisterTypeEncoderFunc("time.Time", func(ptr unsafe.Pointer, stream *jsoniter.Stream) {
		t := *((*time.Time)(ptr))
		stream.WriteString(t.Format("2006-01-02 15:04:05"))
	}, nil)
	//获取数据库
	pool := mysqlDri.Open(dsn)

	constant.Db, err = gorm.Open(pool, &gorm.Config{
		NamingStrategy: namingStrategy,
		Logger:         logger.Default.LogMode(logger.Info),
	})
	Db = constant.Db
	db, err := constant.Db.DB()
	if err != nil {
		println(err.Error())
		println(string(debug.Stack()))
		return err
	}
	db.SetMaxIdleConns(4)                 // 设置数据库连接池中的最大空闲连接数
	db.SetMaxOpenConns(4)                 // 设置数据库的最大打开连接数
	db.SetConnMaxLifetime(time.Hour * 30) // 设置连接的最大生命周期
	db.SetConnMaxIdleTime(time.Hour * 30)
	constant.Pool = db
	constant.GinInstance = setupRouter()
	controller.Init(constant.GinInstance)
	err = constant.GinInstance.Run()
	if err != nil {
		log.Println(err)
		return err
	}
	return err
}

func setupRouter() *gin.Engine {
	r := gin.Default()

	// 注册全局异常恢复中间件
	r.Use(recoveryMiddleware)
	r.Use(static.Serve("/", static.LocalFile("./my-ui", true)))

	// 定义你的路由和处理函数...

	return r
}

// 全局异常处理
func recoveryMiddleware(c *gin.Context) {
	defer func() {
		if err := recover(); err != nil {
			// 记录错误日志
			c.AbortWithStatus(http.StatusInternalServerError)
		}
	}()

	c.Next()
}

// 初始化viper
func initViper() error {
	//viper.AddConfigPath("../")
	dir, _ := os.Getwd()
	println("work目录%s", dir)
	viper.SetEnvPrefix("")
	viper.AutomaticEnv()
	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
	viper.SetConfigFile("settings.yml")
	viper.SetConfigType("yml")
	return viper.ReadInConfig()
}
